/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2023-06-18     cheng       the first version
 */

#include <rtdevice.h>

#define DBG_TAG "pwm_incap"
#define DBG_LVL DBG_WARNING
#include <rtdbg.h>
#include "drivers/PWM_input_capture.h"

static rt_err_t rt_pwm_inputcapture_init(struct rt_device *dev)
{
    rt_err_t ret;
    struct pwm_inputcapture_device *inputcapture;

    RT_ASSERT(dev != RT_NULL);

    ret = RT_EOK;
    inputcapture = (struct pwm_inputcapture_device *)dev;
    if (inputcapture->ops->init)
    {
        ret = inputcapture->ops->init(inputcapture);
    }

    return ret;
}

static rt_err_t rt_pwm_inputcapture_open(struct rt_device *dev, rt_uint16_t oflag)
{
    rt_err_t ret;
    struct pwm_inputcapture_device *inputcapture;

    RT_ASSERT(dev != RT_NULL);

    ret = RT_EOK;
    inputcapture = (struct pwm_inputcapture_device *)dev;

    inputcapture->sem = rt_sem_create("pwm_inputcap_sem", 0, RT_IPC_FLAG_PRIO);
    if(inputcapture->sem == RT_NULL)
        return RT_ERROR;

    if (inputcapture->ops->open)
    {
        ret = inputcapture->ops->open(inputcapture);
    }

    return ret;
}

static rt_err_t rt_pwm_inputcapture_close(struct rt_device *dev)
{
    rt_err_t ret;
    struct pwm_inputcapture_device *inputcapture;

    RT_ASSERT(dev != RT_NULL);

    ret = -RT_ERROR;
    inputcapture = (struct pwm_inputcapture_device *)dev;

    if (inputcapture->ops->close)
    {
        ret = inputcapture->ops->close(inputcapture);
    }

    if (ret != RT_EOK)
    {
        return ret;
    }

    if (inputcapture->sem)
    {
        rt_sem_delete(inputcapture->sem);
        inputcapture->sem = RT_NULL;
    }
    return ret;
}

static rt_ssize_t rt_pwm_inputcapture_read(struct rt_device *dev,
                                 rt_off_t          pos,
                                 void             *buffer,
                                 rt_size_t         size)
{
    struct pwm_inputcapture_device *inputcapture;
    struct pwm_inputcapture_data *pulse_param;

    RT_ASSERT(dev != RT_NULL);

    inputcapture = (struct pwm_inputcapture_device *)dev;
    pulse_param = (struct pwm_inputcapture_data *)buffer;

    pulse_param->pulsecycle_us = inputcapture->pulse_param.pulsecycle_us;
    pulse_param->pulsewidth_us = inputcapture->pulse_param.pulsewidth_us;

    return 1;
}

static rt_err_t rt_pwm_inputcapture_control(struct rt_device *dev, int cmd, void *args)
{
    rt_err_t result;
    struct pwm_inputcapture_device *inputcapture;

    RT_ASSERT(dev != RT_NULL);

    result = RT_EOK;
    inputcapture = (struct pwm_inputcapture_device *)dev;
//    switch (cmd)
//    {
//    default:
//        result = -RT_ENOSYS;
//        break;
//    }

    return result;
}

#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops inputcapture_ops =
{
    rt_pwm_inputcapture_init,
    rt_pwm_inputcapture_open,
    rt_pwm_inputcapture_close,
    rt_pwm_inputcapture_read,
    RT_NULL,
    rt_pwm_inputcapture_control
};
#endif

rt_err_t rt_device_pwm_inputcapture_register(struct pwm_inputcapture_device *inputcapture, const char *name, void *user_data)
{
    struct rt_device *device;

    RT_ASSERT(inputcapture != RT_NULL);
    RT_ASSERT(inputcapture->ops != RT_NULL);

    device = &(inputcapture->parent);

    device->type        = RT_Device_Class_Miscellaneous;
    device->rx_indicate = RT_NULL;
    device->tx_complete = RT_NULL;
    inputcapture->sem = RT_NULL;
    inputcapture->pulse_param.pulsecycle_us = 0;
    inputcapture->pulse_param.pulsewidth_us = 0;

#ifdef RT_USING_DEVICE_OPS
    device->ops         = &inputcapture_ops;
#else
    device->init        = rt_pwm_inputcapture_init;
    device->open        = rt_pwm_inputcapture_open;
    device->close       = rt_pwm_inputcapture_close;
    device->read        = rt_pwm_inputcapture_read;
    device->write       = RT_NULL;
    device->control     = rt_pwm_inputcapture_control;
#endif
    device->user_data   = user_data;

    return rt_device_register(device, name, RT_DEVICE_FLAG_RDONLY | RT_DEVICE_FLAG_STANDALONE);
}

/**
 * This function is ISR for inputcapture interrupt.
 * level: RT_TRUE denotes high level pulse, and RT_FALSE denotes low level pulse.
 */
void rt_hw_pwm_inputcapture_isr(struct pwm_inputcapture_device *inputcapture)
{
    rt_sem_release(inputcapture->sem);
    if (inputcapture->parent.rx_indicate != RT_NULL)
        inputcapture->parent.rx_indicate(&inputcapture->parent, 1);
}
